//=======================================================================
//			Copyright (C) Fire64 2013
//=======================================================================

#include "hud.h"
#include "utils.h"
#include "r_local.h"
#include "r_sprite.h"
#include "mathlib.h"
#include "glsl_shaders.h"
#include "render_config.h"

#ifdef _WIN32
#define SYSTEM_SLASH_CHAR  '\\'
#define SYSTEM_SLASH_STR   "\\"
#endif
#ifdef SYSTEM_POSIX
#define SYSTEM_SLASH_CHAR  '/'
#define SYSTEM_SLASH_STR   "/"
#endif

#define PATHSEPARATOR(c) ((c) == '\\' || (c) == '/')

char* FlipSlashes(char* string)
{
	char* ptr = string;
	if(SYSTEM_SLASH_CHAR == '\\')
	{
		while(ptr = strchr(ptr,'/'))
		{ *ptr = SYSTEM_SLASH_CHAR; }
	}
	else
	{
		while(ptr = strchr(ptr,'\\'))
		{ *ptr = SYSTEM_SLASH_CHAR; }
	}
	return string;
}

void ExtractFileBase (const char *path, char *dest, int destSize)
{
	char *pDestStart = dest;

	if ( destSize <= 1 )
		return;

	const char *src = path + strlen(path) - 1;

//
// back up until a \ or the start
//
	while (src != path && !PATHSEPARATOR(*(src-1)))
		src--;

	while (*src && *src != '.')
	{
		*dest++ = *src++;
		if ( dest - pDestStart >= destSize-1 )
			break;
	}
	*dest = 0;
}

bool CRenderConfig::ShadersInit( char *pShaderType, char *pfile )
{
	char szToken[1024];

	if( !stricmp( pShaderType, "default" ) )
	{
		while( pfile )
		{
			pfile = COM_ParseFile( pfile, szToken );

			if( !Q_stricmp( szToken, "basetexture" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				basetexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}

		}

		if( !isShaderInit )
		{
			isShaderInit = m_GLSLShader.ShaderInit( "base.vert", "base.frag" );
		}

		m_shadertype = SHADER_DEFAULT;
	}
	else if( !stricmp( pShaderType, "sepia" ) )
	{
		while( pfile )
		{
			pfile = COM_ParseFile( pfile, szToken );

			if( !Q_stricmp( szToken, "basetexture" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				basetexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
		}

		if( !isShaderInit )
		{
			isShaderInit = m_GLSLShader.ShaderInit( "sepia.vert", "sepia.frag" );
		}

		m_shadertype = SHADER_SEPIA;
	}
	else if( !stricmp( pShaderType, "inverse" ) )
	{
		while( pfile )
		{
			pfile = COM_ParseFile( pfile, szToken );

			if( !Q_stricmp( szToken, "basetexture" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				basetexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
		}

		if( !isShaderInit )
		{
			isShaderInit = m_GLSLShader.ShaderInit( "inverse.vert", "inverse.frag" );
		}

		m_shadertype = SHADER_INVERSE;
	}
	else if( !stricmp( pShaderType, "monochrome" ) )
	{
		while( pfile )
		{
			pfile = COM_ParseFile( pfile, szToken );

			if( !Q_stricmp( szToken, "basetexture" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				basetexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
		}

		if( !isShaderInit )
		{
			isShaderInit = m_GLSLShader.ShaderInit( "monochrome.vert", "monochrome.frag" );
		}

		m_shadertype = SHADER_MONOCHROME;
	}
	else if( !stricmp( pShaderType, "multytex" ) )
	{
		while( pfile )
		{
			pfile = COM_ParseFile( pfile, szToken );

			if( !Q_stricmp( szToken, "basetexture" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				basetexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
			else if( !Q_stricmp( szToken, "normalmap" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				normaltexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
		}

		if( !isShaderInit )
		{
			isShaderInit = m_GLSLShader.ShaderInit( "multytex.vert", "multytex.frag" );
		}

		m_shadertype = SHADER_MULTYTEX;
	}
	else if( !stricmp( pShaderType, "emboss" ) )
	{
		while( pfile )
		{
			pfile = COM_ParseFile( pfile, szToken );

			if( !Q_stricmp( szToken, "basetexture" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				basetexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
		}

		if( !isShaderInit )
		{
			isShaderInit = m_GLSLShader.ShaderInit( "emboss.vert", "emboss.frag" );
		}

		m_shadertype = SHADER_EMBOSS;
	}
	else if( !stricmp( pShaderType, "detail" ) )
	{
		while( pfile )
		{
			pfile = COM_ParseFile( pfile, szToken );

			if( !Q_stricmp( szToken, "basetexture" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				basetexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
			else if( !Q_stricmp( szToken, "normalmap" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				normaltexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
		}

		if( !isShaderInit )
		{
			isShaderInit = m_GLSLShader.ShaderInit( "detail.vert", "detail.frag" );
		}

		m_shadertype = SHADER_DETAIL;
	}
	else if( !stricmp( pShaderType, "phong" ) )
	{
		while( pfile )
		{
			pfile = COM_ParseFile( pfile, szToken );

			if( !Q_stricmp( szToken, "basetexture" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				basetexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}

		}

		if( !isShaderInit )
		{
			isShaderInit = m_GLSLShader.ShaderInit( "phong.vert", "phong.frag" );
		}

		m_shadertype = SHADER_PHONG;
	}
	else if( !stricmp( pShaderType, "bumpmap" ) )
	{
		while( pfile )
		{
			pfile = COM_ParseFile( pfile, szToken );

			if( !Q_stricmp( szToken, "basetexture" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				basetexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
			else if( !Q_stricmp( szToken, "normalmap" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				normaltexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
		}

		if( !isShaderInit )
		{
			isShaderInit = m_GLSLShader.ShaderInit( "bumpmap.vert", "bumpmap.frag" );
		}

		m_shadertype = SHADER_BUMPMAP;
	}
	else if( !stricmp( pShaderType, "parallaxmap" ) )
	{
		while( pfile )
		{
			pfile = COM_ParseFile( pfile, szToken );

			if( !Q_stricmp( szToken, "basetexture" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				basetexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
			else if( !Q_stricmp( szToken, "normalmap" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				normaltexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
			else if( !Q_stricmp( szToken, "heightmap" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				heighttexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
		}

		if( !isShaderInit )
		{
			isShaderInit = m_GLSLShader.ShaderInit( "parallaxmap.vert", "parallaxmap.frag" );
		}

		m_shadertype = SHADER_PARALLAXMAP;
	}
	else if( !stricmp( pShaderType, "anisohighlight" ) )
	{
		while( pfile )
		{
			pfile = COM_ParseFile( pfile, szToken );

			if( !Q_stricmp( szToken, "basetexture" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				basetexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
			else if( !Q_stricmp( szToken, "normalmap" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				normaltexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
			else if( !Q_stricmp( szToken, "heightmap" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				heighttexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
			else if( !Q_stricmp( szToken, "glossmap" )) 
			{                                          
				pfile = COM_ParseFile( pfile, szToken );
				glosstexid = LOAD_TEXTURE( szToken, NULL, 0, NULL );
			}
		}

		if( !isShaderInit )
		{
			isShaderInit = m_GLSLShader.ShaderInit( "anisohighlight.vert", "anisohighlight.frag" );
		}

		m_shadertype = SHADER_ANISIOHIGHLIGHT;
	}
	else
	{
		return false;
	}

	return true;
}

bool CRenderConfig::LoadRenderConfigForTexture( )
{
	m_shadertype = SHADER_INVALID;
	isRenderSettingValid = false;

	int	currentTex;
	pglGetIntegerv( GL_TEXTURE_BINDING_2D, &currentTex );

	gl_textureid = currentTex;
	m_isInit = true;

	const char *pTextureName = (char *)gRenderfuncs.GL_TextureName( currentTex );

	char pCleanName[MAX_PATH];
	memset( pCleanName, 0, sizeof(pCleanName) );
	ExtractFileBase( pTextureName, pCleanName, sizeof( pCleanName ) );

	char pRenderScriptNsme[MAX_PATH];
	memset( pRenderScriptNsme, 0, sizeof(pRenderScriptNsme) );
	sprintf( pRenderScriptNsme, "scripts/mat_scripts/%s.txt", pCleanName );

	char *afile = (char*)gEngfuncs.COM_LoadFile( pRenderScriptNsme, 5, NULL );
	char *pfile = afile;

	if(!pfile)
	{
//		gEngfuncs.Con_DPrintf( "GLSL Error: Can't load render config: %s\r\n", pRenderScriptName );
		return false;
	}

	char szToken[1024];

	char szShaderType[1024];
	memset( szShaderType, 0, sizeof(szShaderType) );

	while( pfile )
	{
		pfile = COM_ParseFile( pfile, szToken );

		if( !Q_stricmp( szToken, "shadertype" )) 
		{                                          
			pfile = COM_ParseFile( pfile, szToken );
			Q_strcpy( szShaderType, szToken );

			isRenderSettingValid = ShadersInit( szShaderType, pfile );
			break;
		}
	}

	gEngfuncs.COM_FreeFile( afile );

	return isRenderSettingValid;
}

bool CRenderConfig::IsInit( )
{
	return m_isInit;
}

int CRenderConfig::GetTextureID( )
{
	return gl_textureid;
}

ShaderType_t CRenderConfig::GetShaderType( )
{
	return m_shadertype;
}

bool CRenderConfig::ShaderStart( )
{
	if(isRenderSettingValid)
	{
		m_GLSLShader.bind( );

		if( GetShaderType( ) == SHADER_DEFAULT || GetShaderType( ) == SHADER_SEPIA || GetShaderType( ) == SHADER_INVERSE || GetShaderType( ) == SHADER_MONOCHROME || GetShaderType( ) == SHADER_EMBOSS || GetShaderType( ) == SHADER_PHONG )
		{
			GLint baseImageLoc = m_GLSLShader.GetUniformLocation( "baseMap" );

			if(basetexid > 0)
			{
				GL_Bind( GL_TEXTURE0, basetexid );
			}

			pglUniform1iARB( baseImageLoc, 0 );
		}
		else if( GetShaderType( ) == SHADER_MULTYTEX || GetShaderType( ) == SHADER_DETAIL || GetShaderType( ) == SHADER_BUMPMAP )
		{
			GLint baseImageLoc = m_GLSLShader.GetUniformLocation( "baseMap" );
			GLint normalImageLoc = m_GLSLShader.GetUniformLocation( "normalMap" );

			if(basetexid > 0)
			{
				GL_Bind( GL_TEXTURE0, basetexid );
			}

			if(normaltexid > 0)
			{
				GL_Bind( GL_TEXTURE1, normaltexid );
			}

			pglUniform1iARB( baseImageLoc, 0 );
			pglUniform1iARB( normalImageLoc, 1 );
		}
		else if( GetShaderType( ) == SHADER_PARALLAXMAP )
		{
			GLint baseImageLoc = m_GLSLShader.GetUniformLocation( "baseMap" );
			GLint normalImageLoc = m_GLSLShader.GetUniformLocation( "normalMap" );
			GLint heightImageLoc = m_GLSLShader.GetUniformLocation( "heightMap" );

			if(basetexid > 0)
			{
				GL_Bind( GL_TEXTURE0, basetexid );
			}

			if(normaltexid > 0)
			{
				GL_Bind( GL_TEXTURE1, normaltexid );
			}

			if(heighttexid > 0)
			{
				GL_Bind( GL_TEXTURE2, heighttexid );
			}

			pglUniform1iARB( baseImageLoc, 0 );
			pglUniform1iARB( normalImageLoc, 1 );
			pglUniform1iARB( heightImageLoc, 2 );
		}
		else if( GetShaderType( ) == SHADER_ANISIOHIGHLIGHT )
		{
			GLint baseImageLoc = m_GLSLShader.GetUniformLocation( "baseMap" );
			GLint normalImageLoc = m_GLSLShader.GetUniformLocation( "normalMap" );
			GLint heightImageLoc = m_GLSLShader.GetUniformLocation( "heightMap" );
			GLint glossImageLoc = m_GLSLShader.GetUniformLocation( "glossMap" );

			if(basetexid > 0)
			{
				GL_Bind( GL_TEXTURE0, basetexid );
			}

			if(normaltexid > 0)
			{
				GL_Bind( GL_TEXTURE1, normaltexid );
			}

			if(heighttexid > 0)
			{
				GL_Bind( GL_TEXTURE2, heighttexid );
			}

			if(glosstexid > 0)
			{
				GL_Bind( GL_TEXTURE3, glosstexid );
			}

			pglUniform1iARB( baseImageLoc, 0 );
			pglUniform1iARB( normalImageLoc, 1 );
			pglUniform1iARB( heightImageLoc, 2 );
			pglUniform1iARB( glossImageLoc, 3 );
		}
	}

	return true;
}

void CRenderConfig::ShaderStop( )
{
	if( isShaderInit && isRenderSettingValid )
	{
		m_GLSLShader.unbind( );

		if( GetShaderType( ) == SHADER_MULTYTEX || GetShaderType( ) == SHADER_DETAIL || GetShaderType( ) == SHADER_BUMPMAP || GetShaderType( ) == SHADER_PARALLAXMAP || GetShaderType( ) == SHADER_ANISIOHIGHLIGHT )
		{
			GL_CleanUpTextureUnits( 0 );
		}
	}
}